package game_logic.control;

import game_logic.Controller;
import game_logic.model.Board;
import game_logic.model.Piece;
import game_logic.util.Vec2;
import game_logic.view.BoardView;

import javax.swing.*;
import java.util.*;

/**
 * 游戏控制器
 */
public class GameController implements Controller {

    /**
     * 游戏初始化
     */
    public void gameInit(int currentPlayer) {
        this.board.setStalemate(false);
        this.board.setCheckmate(false);
        this.board.setGameOver(false);
        this.board.setCurrentPlayer(currentPlayer);
//        this.board.setWinner(null);
        // 红方
        this.board.setPiece(0, 0, new Piece(0, Piece.Type.Chariot));
        this.board.setPiece(1, 0, new Piece(0, Piece.Type.Horse));
        this.board.setPiece(2, 0, new Piece(0, Piece.Type.Elephant));
        this.board.setPiece(3, 0, new Piece(0, Piece.Type.Guard));
        this.board.setPiece(4, 0, new Piece(0, Piece.Type.King));
        this.board.setPiece(5, 0, new Piece(0, Piece.Type.Guard));
        this.board.setPiece(6, 0, new Piece(0, Piece.Type.Elephant));
        this.board.setPiece(7, 0, new Piece(0, Piece.Type.Horse));
        this.board.setPiece(8, 0, new Piece(0, Piece.Type.Chariot));
        this.board.setPiece(1, 2, new Piece(0, Piece.Type.Cannon));
        this.board.setPiece(7, 2, new Piece(0, Piece.Type.Cannon));
        this.board.setPiece(0, 3, new Piece(0, Piece.Type.Soldier));
        this.board.setPiece(2, 3, new Piece(0, Piece.Type.Soldier));
        this.board.setPiece(4, 3, new Piece(0, Piece.Type.Soldier));
        this.board.setPiece(6, 3, new Piece(0, Piece.Type.Soldier));
        this.board.setPiece(8, 3, new Piece(0, Piece.Type.Soldier));

        // 黑方
        this.board.setPiece(0, 9, new Piece(1, Piece.Type.Chariot));
        this.board.setPiece(1, 9, new Piece(1, Piece.Type.Horse));
        this.board.setPiece(2, 9, new Piece(1, Piece.Type.Elephant));
        this.board.setPiece(3, 9, new Piece(1, Piece.Type.Guard));
        this.board.setPiece(4, 9, new Piece(1, Piece.Type.King));
        this.board.setPiece(5, 9, new Piece(1, Piece.Type.Guard));
        this.board.setPiece(6, 9, new Piece(1, Piece.Type.Elephant));
        this.board.setPiece(7, 9, new Piece(1, Piece.Type.Horse));
        this.board.setPiece(8, 9, new Piece(1, Piece.Type.Chariot));
        this.board.setPiece(1, 7, new Piece(1, Piece.Type.Cannon));
        this.board.setPiece(7, 7, new Piece(1, Piece.Type.Cannon));
        this.board.setPiece(0, 6, new Piece(1, Piece.Type.Soldier));
        this.board.setPiece(2, 6, new Piece(1, Piece.Type.Soldier));
        this.board.setPiece(4, 6, new Piece(1, Piece.Type.Soldier));
        this.board.setPiece(6, 6, new Piece(1, Piece.Type.Soldier));
        this.board.setPiece(8, 6, new Piece(1, Piece.Type.Soldier));

    }

    @Override
    public void gameStart() {
        gameViewUpdate();
    }

    @Override
    public void gameViewUpdate() {
        this.boardView.display(this.board);
    }

    @Override
    public void gamePause() {

    }

    @Override
    public void gameContinue() {

    }

    @Override
    public boolean move(int sx, int sy, int tx, int ty) {
        if (!(0 <= sx && sx <= 8 && 0 <= sy && sy <= 9) || !(0 <= tx && tx <= 8 && 0 <= ty && ty <= 9)) {
            System.out.println("坐标在棋盘外");
            gameViewUpdate();
            return false;
        }
        Piece srcPiece = this.board.getPiece(sx, sy), tarPiece = this.board.getPiece(tx, ty);
        if (srcPiece == null) {
            System.out.println("点击的位置没有棋子");
            gameViewUpdate();
            return false;
        }
        if (srcPiece.getOwner() != this.board.getCurrentPlayer()) {
            System.out.println("禁止移动非己方棋子");
            gameViewUpdate();
            return false;
        }
        if (!this.moveController.moveIfLegal(this.board, new Vec2(sx, sy), new Vec2(tx, ty))) { // 未移动
            System.out.println("移动失败");
            gameViewUpdate();
            return false;
        }
        // 已经成功移动
        if (tarPiece != null && tarPiece.getType() == Piece.Type.King) { // 国王被吃了，游戏结束
            this.board.setGameOver(true);
            this.board.setWinner(this.board.getCurrentPlayer());
            gameViewUpdate();
            new Thread(new Runnable() {
                public void run() {
                    if (board.getWinner() == 0) {
                        JOptionPane.showMessageDialog(null, "红方胜利！");
                    } else {
                        JOptionPane.showMessageDialog(null, "黑方胜利！");
                    }
                }
            }).start();
            // 有人赢了
            return true;
        }
        // 游戏没有结束，更换出手方
        this.board.setCurrentPlayer((this.board.getCurrentPlayer() + 1) % 2);
        this.board.setCheckmate(this.isCheckmate());
        gameViewUpdate();
        return true;
    }


    /**
     * @return 是否在将军
     */
    private boolean isCheckmate() {
        Set<Vec2>[] movable = new HashSet[]{new HashSet<Vec2>(), new HashSet<Vec2>()};
//        for (int i = 0; i < movable.length; ++i) movable[i] = ;
        Vec2[] kings = new Vec2[2];
        for (int x = 0; x < 9; ++x) {
            for (int y = 0; y < 10; ++y) {
                Piece piece = this.board.getPiece(x, y);
                if (piece == null) continue;
                movable[piece.getOwner()].addAll(this.moveController.getMovablePosition(this.board, new Vec2(x, y)));
                if (piece.getType() == Piece.Type.King) kings[piece.getOwner()] = new Vec2(x, y);
            }
        }
        return movable[0].contains(kings[1]) || movable[1].contains(kings[0]);
    }

    public int getWhoWin() {
        return this.board.getCurrentPlayer();
    }

    /**
     * 构造函数，传入所控制的棋盘、移动控制器。并初始化游戏（棋子布局、游戏状态等）
     *
     * @param board          所控制的棋盘
     * @param moveController 移动控制器
     */
    public GameController(Board board, MoveController moveController, BoardView boardView, boolean redFirst) {
        this.board = board;
        this.moveController = moveController;
        this.boardView = boardView;
        this.gameInit(redFirst ? 0 : 1);
    }

    /**
     * 返回piece position
     *
     * @param piece
     * @return
     */
    public Vec2 getPiecePos(Piece piece) {
        return this.moveController.getPiecePos(this.board, piece);
    }

    /**
     * 返回board
     *
     * @return board
     */
    public Board getBoard() {
        return board;
    }


    private final Board board; // 游戏棋盘
    private final MoveController moveController; // 移动控制器

    private final BoardView boardView; // 棋盘视图

}
